﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Linq.Extensions;
using Abp.Runtime.Session;
using LeadThing.AbpZeroTemplate.Authorization.Roles;
using LeadThing.AbpZeroTemplate.Authorization.Roles.Dto;
using LeadThing.AbpZeroTemplate.Authorization.Users;
using LeadThing.AbpZeroTemplate.CallPolices.Authorization;
using LeadThing.AbpZeroTemplate.CallPolices.Dtos;
using LeadThing.AbpZeroTemplate.CallTypes;
using LeadThing.AbpZeroTemplate.Dto;
using LeadThing.AbpZeroTemplate.Files;
using LeadThing.AbpZeroTemplate.Map;
using LeadThing.AbpZeroTemplate.WorkFlow_Processs;
using LeadThing.AbpZeroTemplate.WorkFlow_Run_Processs;
using LeadThing.AbpZeroTemplate.WorkFlow_Runs;
using LeadThing.AbpZeroTemplate.WorkFlow_TableNames;
using LeadThing.AbpZeroTemplate.WorkFlows;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Threading.Tasks;
using static LeadThing.AbpZeroTemplate.Configuration.AppSettings;

namespace LeadThing.AbpZeroTemplate.CallPolices
{
    /// <summary>
    /// 一键报警表服务实现
    /// </summary>

    public class CallPoliceAppService : AbpZeroTemplateAppServiceBase, ICallPoliceAppService
    {
        private readonly IRepository<CallPolice, long> _callPoliceRepository;
        private readonly ICallPoliceListExcelExporter _callPoliceListExcelExporter;
        private readonly IRepository<CallType, long> _callTypeRepository;
        private readonly IRepository<User, long> _userRepository;//用户
        private readonly IRoleAppService _roleService;//角色
        private readonly IRepository<File, long> _fileRepository;

        //工作流
        private readonly IRepository<WorkFlow, long> _workFlowRepository;//流程表

        private readonly IRepository<WorkFlow_Process, long> _workFlow_ProcessRepository;//流程节点配置表
        private readonly IRepository<WorkFlow_Run, long> _workFlow_RunRepository;//流程实例表
        private readonly IRepository<WorkFlow_Run_Process, long> _workFlow_Run_ProcessRepository;//实例节点流转明细
        private readonly IRepository<WorkFlow_TableName, long> _workFlow_TableNameRepository;

        private readonly CallPoliceManage _callPoliceManage;
        private readonly WorkFlowManage _workFlowManage;

        /// <summary>
        /// 构造方法
        /// </summary>
        public CallPoliceAppService(IRepository<CallPolice, long> callPoliceRepository,
CallPoliceManage callPoliceManage
      , ICallPoliceListExcelExporter callPoliceListExcelExporter
      , IRepository<CallType, long> callTypeRepository
      , IRepository<WorkFlow, long> workFlowRepository
      , IRepository<WorkFlow_Process, long> workFlow_ProcessRepository
      , IRepository<WorkFlow_Run, long> workFlow_RunRepository
      , IRepository<WorkFlow_Run_Process, long> workFlow_Run_ProcessRepository
      , IRepository<WorkFlow_TableName, long> workFlow_TableNameRepository
      , WorkFlowManage workFlowManage
      , IRepository<User, long> userRepository
      , IRoleAppService roleService
      , IRepository<File, long> fileRepository
  )
        {
            _callPoliceRepository = callPoliceRepository;
            _callPoliceManage = callPoliceManage;
            _callPoliceListExcelExporter = callPoliceListExcelExporter;
            _callTypeRepository = callTypeRepository;
            _workFlowRepository = workFlowRepository;
            _workFlow_ProcessRepository = workFlow_ProcessRepository;
            _workFlow_RunRepository = workFlow_RunRepository;
            _workFlow_Run_ProcessRepository = workFlow_Run_ProcessRepository;
            _workFlow_TableNameRepository = workFlow_TableNameRepository;
            _workFlowManage = workFlowManage;
            _userRepository = userRepository;
            _roleService = roleService;
            _fileRepository = fileRepository;
        }

        #region 实体的自定义扩展方法

        private IQueryable<CallPolice> _callPoliceRepositoryAsNoTrack => _callPoliceRepository.GetAll().AsNoTracking();

        /// <summary>
        /// 根据查询条件获取一键报警表列表
        /// </summary>
        public async Task<ListResultDto<CallPoliceListDto>> GetCallPolicesByWhereAsync(GetCallPoliceInput input)
        {
            var query = _callPoliceRepositoryAsNoTrack;

            #region 权限验证

            var userID = AbpSession.GetUserId();
            var userModel = _userRepository.FirstOrDefault(userID);
            GetRolesInput input_role = new GetRolesInput() { UserId = userID };
            var role = await _roleService.GetRolesByUserId(input_role);

            if (role.DisplayName == "乡镇网格管理员")
                query = query.Where(p => p.TownID == userModel.TownID || p.CreatorUserId == userID);
            else if (role.DisplayName == "社区网格管理员")
                query = query.Where(p => p.AreaID == userModel.AreaID || p.CreatorUserId == userID);
            else if (role.DisplayName == "村庄网格管理员")
                query = query.Where(p => p.VillageID == userModel.VillageID || p.CreatorUserId == userID);

            #endregion

            //TODO:根据传入的参数添加过滤条件

            #region 根据传入的参数添加过滤条件

            if (!string.IsNullOrWhiteSpace(input.Filter))
            {
                query = query.Where(p => p.Address.Contains(input.Filter));
            }

            if (input.Status != 0)
            {
                if (input.endStaus != 0)
                    query = query.Where(p => p.Status == input.Status || p.Status == input.endStaus);
                else
                    query = query.Where(p => p.Status == input.Status);
            }

            #endregion 根据传入的参数添加过滤条件

            var callPoliceCount = await query.CountAsync();

            var callPolices = await query
            .OrderByDescending(p => p.Id)
            .PageBy(input)
            .ToListAsync();

            var callTypeList = _callTypeRepository.GetAll();
            var workflowList = from wf_run in _workFlow_RunRepository.GetAll()
                               join wf_run_process in _workFlow_Run_ProcessRepository.GetAll()
                               on wf_run.Id equals wf_run_process.RunID
                               select new { wf_run.DetailID, wf_run_process.ProcessType };

            return new ListResultDto<CallPoliceListDto>(
            callPolices.Select(item =>
            {
                var dto = item.MapTo<CallPoliceListDto>();
                var callTypeModel = callTypeList.Where(p => p.Id == dto.CallTypeID).FirstOrDefault();

                if (callTypeModel != null)
                    dto.CallTypeName = callTypeModel.Title;

                var wfList = workflowList.Where(p => p.DetailID == dto.Id && p.ProcessType == "is_end").ToList();
                if (wfList.Count > 0)
                    dto.ShowMenu = false;
                else
                    dto.ShowMenu = true;

                var creator = _userRepository.GetAll().Where(p => p.Id == item.CreatorUserId).FirstOrDefault();
                if (creator != null)
                {
                    dto.CreatUserName = creator.Name;
                }

                return dto;
            }).ToList());
        }

        #endregion 实体的自定义扩展方法

        #region 一键报警表管理

        /// <summary>
        /// 根据查询条件获取一键报警表分页列表
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice)]
        public async Task<PagedResultDto<CallPoliceListDto>> GetPagedCallPolicesAsync(GetCallPoliceInput input)
        {
            var query = _callPoliceRepositoryAsNoTrack;

            #region 权限验证

            var userID = AbpSession.GetUserId();
            var userModel = _userRepository.FirstOrDefault(userID);
            GetRolesInput input_role = new GetRolesInput() { UserId = userID };
            var role = await _roleService.GetRolesByUserId(input_role);

            if (role.DisplayName == "乡镇网格管理员")
                query = query.Where(p => p.TownID == userModel.TownID || p.CreatorUserId == userID);
            else if (role.DisplayName == "社区网格管理员")
                query = query.Where(p => p.AreaID == userModel.AreaID || p.CreatorUserId == userID);
            else if (role.DisplayName == "村庄网格管理员")
                query = query.Where(p => p.VillageID == userModel.VillageID || p.CreatorUserId == userID);

            #endregion

            //TODO:根据传入的参数添加过滤条件

            #region 根据传入的参数添加过滤条件

            if (!string.IsNullOrWhiteSpace(input.Filter))
            {
                query = query.Where(p => p.Address.Contains(input.Filter));
            }

            if (input.Status != 0)
            {
                if (input.endStaus != 0)
                    query = query.Where(p => p.Status == input.Status || p.Status == input.endStaus);
                else
                    query = query.Where(p => p.Status == input.Status);
            }

            #endregion 根据传入的参数添加过滤条件

            var callPoliceCount = await query.CountAsync();

            var callPolices = await query
            .OrderByDescending(p => p.Id)
            .PageBy(input)
            .ToListAsync();

            var callTypeList = _callTypeRepository.GetAll();
            var workflowList = from wf_run in _workFlow_RunRepository.GetAll()
                               join wf_run_process in _workFlow_Run_ProcessRepository.GetAll()
                               on wf_run.Id equals wf_run_process.RunID
                               select new { wf_run.DetailID, wf_run_process.ProcessType };

            return new PagedResultDto<CallPoliceListDto>(
            callPoliceCount,
            callPolices.Select(item =>
            {
                var dto = item.MapTo<CallPoliceListDto>();
                var callTypeModel = callTypeList.Where(p => p.Id == dto.CallTypeID).FirstOrDefault();

                if (callTypeModel != null)
                    dto.CallTypeName = callTypeModel.Title;

                var wfList = workflowList.Where(p => p.DetailID == dto.Id && p.ProcessType == "is_end").ToList();
                if (wfList.Count > 0)
                    dto.ShowMenu = false;
                else
                    dto.ShowMenu = true;

                return dto;
            }).ToList());
        }

        /// <summary>
        /// 通过Id获取一键报警表信息进行编辑或修改
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice)]
        public async Task<GetCallPoliceForEditOutput> GetCallPoliceForEditAsync(NullableIdDto<long> input)
        {
            var output = new GetCallPoliceForEditOutput();

            CallPoliceEditDto callPoliceEditDto;

            if (input.Id.HasValue)
            {
                var entity = await _callPoliceRepository.GetAsync(input.Id.Value);
                callPoliceEditDto = entity.MapTo<CallPoliceEditDto>();

                var fileModel = _fileRepository.GetAll().Where(p => p.Id == callPoliceEditDto.FileID).FirstOrDefault();
                if (fileModel != null)
                    callPoliceEditDto.FileUrl = AppSetting.AppUrl + fileModel.Url;

                var userModel = _userRepository.GetAll().Where(p => p.Id == entity.CreatorUserId).FirstOrDefault();
                if (userModel != null)
                {
                    callPoliceEditDto.Name = userModel.Name;
                    callPoliceEditDto.PhoneNumber = userModel.PhoneNumber;
                }
            }
            else
            {
                callPoliceEditDto = new CallPoliceEditDto();
            }

            output.CallPolice = callPoliceEditDto;
            return output;
        }

        /// <summary>
        /// 通过指定id获取一键报警表ListDto信息
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice)]
        public async Task<CallPoliceListDto> GetCallPoliceByIdAsync(EntityDto<long> input)
        {
            var entity = await _callPoliceRepository.GetAsync(input.Id);

            return entity.MapTo<CallPoliceListDto>();
        }

        /// <summary>
        /// 新增或更改一键报警表
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice)]
        public async Task CreateOrUpdateCallPoliceAsync(CreateOrUpdateCallPoliceInput input)
        {
            if (input.CallPoliceEditDto.Id.HasValue)
            {
                await UpdateCallPoliceAsync(input.CallPoliceEditDto);
            }
            else
            {
                await CreateCallPoliceAsync(input.CallPoliceEditDto);
            }
        }

        /// <summary>
        /// 新增一键报警表
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice_CreateCallPolice)]
        public virtual async Task<CallPoliceEditDto> CreateCallPoliceAsync(CallPoliceEditDto input)
        {
            //TODO:新增前的逻辑判断，是否允许新增

            var entity = input.MapTo<CallPolice>();

            #region 获取发起节点ID

            //获取发起节点ID
            var query = from process in _workFlow_ProcessRepository.GetAll()
                        join table in _workFlow_TableNameRepository.GetAll()
                        on process.TableID equals table.Id
                        where table.TableName == "CallPolice"
                        select new { process.Id, process.ProcessOrder, process.TableID, process.FlowID };

            var wf_ProcessModel = query.OrderBy(p => p.ProcessOrder).FirstOrDefault();

            #endregion 获取发起节点ID

            entity.Status = Convert.ToInt32(wf_ProcessModel.Id);//赋值发起节点ID

            //先执行新增纠纷操作
            entity.Id = await _callPoliceRepository.InsertAndGetIdAsync(entity);

            //添加工作流
            _workFlowManage.AuditStart(Convert.ToInt32(entity.Id), Convert.ToInt32(wf_ProcessModel.Id), "发起一个一键报警事件", Convert.ToInt32(wf_ProcessModel.Id), wf_ProcessModel.FlowID);

            return entity.MapTo<CallPoliceEditDto>();
        }

        /// <summary>
        /// 编辑一键报警表
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice_EditCallPolice)]
        public virtual async Task UpdateCallPoliceAsync(CallPoliceEditDto input)
        {
            //TODO:更新前的逻辑判断，是否允许更新

            var entity = await _callPoliceRepository.GetAsync(input.Id.Value);
            input.MapTo(entity);

            #region 获取当前节点的下一节点

            //获取当前节点的下一节点
            var wfProcess = _workFlow_ProcessRepository;
            var wf_ProcessModel = wfProcess.FirstOrDefault(entity.Status);

            #endregion 获取当前节点的下一节点

            #region 获取FlowID

            //获取FlowID
            var query = from process in _workFlow_ProcessRepository.GetAll()
                        join table in _workFlow_TableNameRepository.GetAll()
                        on process.TableID equals table.Id
                        where table.TableName == "CallPolice"
                        select new { process.Id, process.ProcessOrder, process.TableID, process.FlowID };
            var wfProcessNewModel = query.FirstOrDefault();

            #endregion 获取FlowID

            //添加工作流
            _workFlowManage.AuditStart(Convert.ToInt32(entity.Id), entity.Status, input.ProcessContent, Convert.ToInt32(wf_ProcessModel.ProcessTo), wfProcessNewModel.FlowID);
            entity.Status = Convert.ToInt32(wf_ProcessModel.ProcessTo);//赋值下一节点ID

            await _callPoliceRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 删除一键报警表
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice_DeleteCallPolice)]
        public async Task DeleteCallPoliceAsync(EntityDto<long> input)
        {
            //TODO:删除前的逻辑判断，是否允许删除
            await _callPoliceRepository.DeleteAsync(input.Id);
        }

        /// <summary>
        /// 批量删除一键报警表
        /// </summary>
        [AbpAuthorize(CallPoliceAppPermissions.CallPolice_DeleteCallPolice)]
        public async Task BatchDeleteCallPoliceAsync(List<long> input)
        {
            //TODO:批量删除前的逻辑判断，是否允许删除
            await _callPoliceRepository.DeleteAsync(s => input.Contains(s.Id));
        }

        #endregion 一键报警表管理

        #region 一键报警表的Excel导出功能

        public async Task<FileDto> GetCallPoliceToExcel()
        {
            var entities = await _callPoliceRepository.GetAll().ToListAsync();

            var dtos = entities.MapTo<List<CallPoliceListDto>>();

            var fileDto = _callPoliceListExcelExporter.ExportCallPoliceToFile(dtos);

            return fileDto;
        }

        #endregion 一键报警表的Excel导出功能

        #region APP接口

        /// <summary>
        /// 新增一键报警表
        /// </summary>
        public virtual async Task<CallPoliceEditDto> CreateCallPoliceAPPAsync(CallPoliceEditAPPDto input)
        {
            //TODO:新增前的逻辑判断，是否允许新增

            var entity = input.MapTo<CallPolice>();

            //获取发起节点ID
            var query = from process in _workFlow_ProcessRepository.GetAll()
                        join table in _workFlow_TableNameRepository.GetAll()
                        on process.TableID equals table.Id
                        where table.TableName == "CallPolice"
                        select new { process.Id, process.ProcessOrder, process.TableID };

            var wf_ProcessModel = query.OrderBy(p => p.ProcessOrder).FirstOrDefault();
            entity.Status = Convert.ToInt32(wf_ProcessModel.Id);//赋值发起节点ID

            //转换坐标系
            double oldX = 0, oldY = 0;
            double.TryParse(entity.XPoint, out oldX);
            double.TryParse(entity.YPoint, out oldY);

            var newPoint = PositionHelper.bd09_To_Gps84(oldY, oldX);
            entity.XPoint = newPoint.getWgLon().ToString();
            entity.YPoint = newPoint.getWgLat().ToString();

            //先执行新增纠纷操作
            entity.Id = await _callPoliceRepository.InsertAndGetIdAsync(entity);

            //添加工作流
            _workFlowManage.AuditStart(Convert.ToInt32(entity.Id), Convert.ToInt32(wf_ProcessModel.Id), "发起一个一键报警事件", Convert.ToInt32(wf_ProcessModel.Id), 2);

            return entity.MapTo<CallPoliceEditDto>();
        }

        #endregion APP接口
    }
}